package jf.jextn.converter;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import jf.jextn.JExtn;
import jf.jextn.util.ReflectionUtil;

public class ValueOfConverter<O> implements StringValueConverter<O> {

    private Class<O> type;

    private Method valueOfMethod;

    public ValueOfConverter(Class<O> type) {
        JExtn.checkNull(type, "type is required");

        Method m = ReflectionUtil.findMethod(type, "valueOf", String.class);
        if (!(Modifier.isStatic(m.getModifiers()) && type.isAssignableFrom(m.getReturnType()))) {

            String msg = String.format("public static {0} valueOf(String.class) {...} method is needed",
                    type.getName());

            throw new IllegalArgumentException(msg);
        }

        this.type = type;
        this.valueOfMethod = m;
    }

    @Override
    public O from(String value) {
        try {
            Object o =  valueOfMethod.invoke(null, value);

            return type.cast(o);
        } catch (IllegalArgumentException e) {
            throw new ConversionException("It should not happen. Please review implementation", e);
        } catch (IllegalAccessException e) {
            throw new ConversionException("It should not happen. Please review implementation", e);
        } catch (InvocationTargetException e) {
            throw new ConversionException("valueOf(String) method failed.", e.getCause());
        }
    }

    @Override
    public String to(O o) {
        return String.valueOf(o);
    }

}
